#include "stm32f10x.h"                  // Device header
#include "MySPI.h"
#include "led.h"
/**
	* @brief  SS写。其中A4输出片选信号SS
	* @retval None
  */
void MySPI_W_SS(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue);
}

/**
	* @brief  进行SPI初始化，将采用SPI模式0进行通信。SPI要求主机的输入引脚初始化为浮空或上拉输入，输出为推挽输出。此处默认采用A4输出片选信号；A5输出时钟信
						号；A6：从机输出，主机输入；A7：主机输出，从机输入。这与STM32硬件进行SPI通信用到的引脚是相同的。其中对于主机STM32而言，A4、A5、A7都是输出引
						脚，A6是输入引脚。默认选用SPI1
  * @retval None
  */
void MySPI_Init(void)
{
	gpio_Init(RCC_APB2Periph_GPIOA, GPIOA, GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7, GPIO_Mode_Out_PP);//通用推挽输出
	gpio_Init(RCC_APB2Periph_GPIOA, GPIOA, GPIO_Pin_5 | GPIO_Pin_7, GPIO_Mode_AF_PP);//复用推挽输出
	gpio_Init(RCC_APB2Periph_GPIOA, GPIOA, GPIO_Pin_6, GPIO_Mode_IPU);//上拉输入。模式的选择是根据手册的要求进行的
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);//STM32的两套硬件SPI资源：SPI1和SPI2分别是用APB2、APB1两个时钟控制的，二者初始化函数并不相同，
	//此处默认选用SPI1
	SPI_InitTypeDef SPI_InitStructure;
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//默认将STM32作为主机
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//配置裁剪引脚的参数，最正常的使用方式是双线全双工
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//数据帧。16位数据帧也不过是连续发送两个8位数据而已，所以使用8位数据帧就好
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//高位/低位先行。一般都是高位先行，这两个都没有什么修改的必要，故不提取成参数
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;//波特率预分频器，配置SCK时钟的频率。不是很追求速度的话就选128分频吧
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;//工作时默认电平。因为是选用的模式0进行初始化的，此处选择低电平，一旦NSS置0，从机开始与主机通信
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//在哪个边缘处进行数据移出。因为此处选择的是模式0，所以选择第一个边缘
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//我们选择软件模拟NSS引脚
	SPI_InitStructure.SPI_CRCPolynomial = 7;//不太用得到的参数，给个默认值7
	SPI_Init(SPI1, &SPI_InitStructure);
	SPI_Cmd(SPI1, ENABLE);
	MySPI_W_SS(1);//默认不选中从机
}

/**
	* @brief  SPI起始命令，即从机使能
  * @retval None
  */
void MySPI_Start(void)
{
	MySPI_W_SS(0);
}

/**
	* @brief  SPI终止命令，即从机失能
  * @retval None
  */
void MySPI_Stop(void)
{
	MySPI_W_SS(1);
}

/**
* @brief  模式0下进行SPI互换字节。此处选择非连续传输，尽管会损失一些性能，但过程是十分简单明了的
	* @param  ByteSend: 要发送的数据
	* @retval 从机发来的一字节数据
  */
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{
	while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);//等到发送寄存器空了才开始进行数据发送。除非硬件电路出了问题，否则是不会卡死的，此处
	//不进行超时的处理
	SPI_I2S_SendData(SPI1, ByteSend);//软件写入数据至DR，此步骤会同时清除TXE标志位
	while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);//等到主机发送（即从机接收）完成才开始进行数据接收
	return SPI_I2S_ReceiveData(SPI1);
}
